﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Dubbo.Rpc.Protocol
{
    public class ProtocolFilterWrapper : IProtocol
    {
        private readonly IProtocol protocol;

        public ProtocolFilterWrapper(IProtocol protocol)
        {
            if (protocol == null)
            {
                throw new ArgumentNullException("protocol == null");
            }
            this.protocol = protocol;
        }

        public int GetDefaultPort()
        {
            return protocol.GetDefaultPort();
        }

        public IExporter<T> Export<T>(IInvoker<T> invoker)
        {
            //if (Constants.REGISTRY_PROTOCOL.equals(invoker.Url.Protocol))
            //{
            //    return protocol.Export(invoker);
            //}
            //return protocol.Export(buildInvokerChain(invoker, Constants.SERVICE_FILTER_KEY, Constants.PROVIDER));
            return protocol.Export(invoker);
        }

        public IInvoker<T> Refer<T>(URL url)
        {
            //if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) {
            //    return protocol.refer(type, url);
            //}
            //return buildInvokerChain(protocol.refer(type, url), Constants.REFERENCE_FILTER_KEY, Constants.CONSUMER);
            return protocol.Refer<T>(url);
        }

        public void Destroy()
        {
            protocol.Destroy();
        }

        private static IInvoker<T> BuildInvokerChain<T>(IInvoker<T> invoker, string key, string group)
        {
            IInvoker<T> last = invoker;
            //List<IFilter> filters = ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(invoker.getUrl(), key, group);
            List<IFilter> filters = new List<IFilter>();

            if (filters.Count > 0)
            {
                for (int i = filters.Count - 1; i >= 0; i--)
                {
                    IFilter filter = filters[i];
                    last = new ChainInvoker<T>(invoker, last, filter);
                }
            }
            return last;
        }

        class ChainInvoker<T> : IInvoker<T>
        {
            private IInvoker<T> invoker;
            private IInvoker<T> next;
            private IFilter filter;

            public ChainInvoker(IInvoker<T> invoker, IInvoker<T> next, IFilter filter)
            {
                this.invoker = invoker;
                this.next = next;
                this.filter = filter;
            }
            
            public URL Url { get { return invoker.Url; } }

            public bool IsAvailable { get { return invoker.IsAvailable; } }
                
            public IResult Invoke(IInvocation<T> invocation)
            {
                return filter.Invoke(next, invocation);
            }

            public void Destroy()
            {
                invoker.Destroy();
            }
            
            public override string ToString()
            {
                return invoker.ToString();
            }
        }

    }
}
